package com.kingwang.demo.springsecuritytokendemo.security;

import com.kingwang.demo.springsecuritytokendemo.config.SessionConfig;
import com.kingwang.demo.springsecuritytokendemo.utils.AuthenticationTokenUtils;
import com.kingwang.demo.springsecuritytokendemo.utils.DateTimeGenerator;
import org.springframework.security.core.userdetails.UserDetails;

import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import java.security.NoSuchAlgorithmException;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class InMemoryTokenSessionManager extends AbstractTokenSessionManager {
    private Map<String, TokenSession> sessions = new ConcurrentHashMap<>();

    private Map<String, LocalDateTime> sessionActiveTimes = new ConcurrentHashMap<>();

    public InMemoryTokenSessionManager(SessionConfig sessionConfig, DateTimeGenerator dateTimeGenerator) {
        super(sessionConfig, dateTimeGenerator);
    }

    @Override
    public TokenSession getSession(String id) {
        TokenSession result = this.sessions.get(id);

        return result;
    }

    @Override
    public Collection<TokenSession> getSessions() {
        return Collections.unmodifiableCollection(this.sessions.values());
    }

    @Override
    public void refreshSession(TokenSession session) {
        LocalDateTime lastActiveTime = this.dateTimeGenerator.now();

        TokenSession savedSession = this.sessions.get(session.getId());

        if (savedSession instanceof AbstractTokenSession && lastActiveTime != null) {
            ((AbstractTokenSession) savedSession).setLastActiveTime(lastActiveTime);
        }

        this.sessionActiveTimes.put(session.getId(), lastActiveTime);
    }

    @Override
    public void removeSession(String id) {
        this.sessions.remove(id);
    }

    @Override
    protected TokenSession doCreateSession(String tokenType, String token, UserDetails userDetails) {
        String id = this.generateSessionId(tokenType, token);

        InMemoryTokenSession result = new InMemoryTokenSession(id, tokenType, token, this);

        LocalDateTime now = this.dateTimeGenerator.now();

        result.setCreationTime(now);
        result.setLastActiveTime(now);
        result.setUsername(userDetails.getUsername());
        result.setUserDetails(userDetails);

        this.sessions.put(id, result);
        this.sessionActiveTimes.put(id, now);

        return result;
    }

    @Override
    protected String generateTokenByUserDetails(UserDetails userDetails) throws BadPaddingException,
            NoSuchAlgorithmException, IllegalBlockSizeException {
        String seed = userDetails.getUsername() + "_" + System.currentTimeMillis();

        return AuthenticationTokenUtils.generateToken(seed);
    }
}
